package com.judge.config;

import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.netty.NettyDockerCmdExecFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@Slf4j
public class DockerSandBoxPoolConfig {

    @Value("${sandbox.docker.host:unix:///var/run/docker.sock}")
    private String dockerHost;

    @Value("${sandbox.docker.image:openjdk:17-jdk-alpine}")
    private String sandboxImage;

    @Value("${sandbox.docker.volume:/usr/share/java}")
    private String volumeDir;

    @Value("${sandbox.limit.memory:268435456}") // 256MB
    private Long memoryLimit;

    @Value("${sandbox.limit.memory-swap:268435456}") // 256MB
    private Long memorySwapLimit;

    @Value("${sandbox.limit.cpu:1}")
    private Long cpuLimit;

    @Value("${sandbox.docker.pool.size:4}")
    private int poolSize;

    @Value("${sandbox.docker.name-prefix:oj-sandbox-jdk}")
    private String containerNamePrefix;

    @Bean
    public DockerClient createDockerClient() {
        log.info("正在创建Docker客户端，连接地址: {}", dockerHost);

        try {
            DefaultDockerClientConfig clientConfig = DefaultDockerClientConfig.createDefaultConfigBuilder()
                    .withDockerHost(dockerHost)
                    .build();

            // 使用Netty Exec Factory，它支持Unix Socket
            NettyDockerCmdExecFactory nettyDockerCmdExecFactory = new NettyDockerCmdExecFactory();
            nettyDockerCmdExecFactory.withConnectTimeout(30000);
            nettyDockerCmdExecFactory.withReadTimeout(30000);

            DockerClient dockerClient = DockerClientBuilder
                    .getInstance(clientConfig)
                    .withDockerCmdExecFactory(nettyDockerCmdExecFactory)
                    .build();

            // 测试连接
            dockerClient.pingCmd().exec();
            log.info("Docker连接成功: {}", dockerHost);

            return dockerClient;

        } catch (Exception e) {
            log.error("主要连接方式失败: {}", dockerHost, e);

            // 尝试备用连接方案
            return tryFallbackConnections();
        }
    }

    /**
     * 备用连接方案
     */
    private DockerClient tryFallbackConnections() {
        String[] fallbackHosts = {
                "unix:///var/run/docker.sock",  // Unix Socket
                "tcp://localhost:2375",         // 本地TCP
                "tcp://127.0.0.1:2375"          // 本地TCP
        };

        for (String host : fallbackHosts) {
            try {
                log.info("尝试备用连接: {}", host);

                DefaultDockerClientConfig clientConfig = DefaultDockerClientConfig.createDefaultConfigBuilder()
                        .withDockerHost(host)
                        .build();

                NettyDockerCmdExecFactory nettyDockerCmdExecFactory = new NettyDockerCmdExecFactory();
                nettyDockerCmdExecFactory.withConnectTimeout(10000);
                nettyDockerCmdExecFactory.withReadTimeout(10000);

                DockerClient dockerClient = DockerClientBuilder
                        .getInstance(clientConfig)
                        .withDockerCmdExecFactory(nettyDockerCmdExecFactory)
                        .build();

                dockerClient.pingCmd().exec();
                log.info("✓ 备用连接成功: {}", host);

                // 记录成功的连接方式，便于后续配置
                log.warn("建议将 sandbox.docker.host 配置为: {}", host);

                return dockerClient;

            } catch (Exception e) {
                log.warn("备用连接失败 {}: {}", host, e.getMessage());
            }
        }

        String errorMsg = "所有Docker连接方式都失败了。请检查：\n" +
                "1. Docker服务是否运行\n" +
                "2. Unix Socket权限是否正确\n" +
                "3. TCP端口是否开启\n" +
                "4. 应用程序是否有足够权限";
        log.error(errorMsg);
        throw new RuntimeException(errorMsg);
    }

    @Bean
    public DockerSandBoxPool createDockerSandBoxPool(DockerClient dockerClient) {
        DockerSandBoxPool dockerSandBoxPool = new DockerSandBoxPool(dockerClient, sandboxImage, volumeDir, memoryLimit,
                memorySwapLimit, cpuLimit, poolSize, containerNamePrefix);
        dockerSandBoxPool.initDockerPool();
        return dockerSandBoxPool;
    }
}